package com.itcam.sort.quicksort;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author : Cammy.Wu
 * Description : 双边循环快排
 */

public class QuickSortHoare {

    public static void main(String[] args) {
        int[] a = {9, 5, 7, 12, 1, 3};
        System.out.println(Arrays.toString(a));
        quickSort(a);
        System.out.println(Arrays.toString(a));
    }

    public static void quickSort(int[] a) {
        quick(a, 0, a.length - 1);
    }

    public static void quick(int[] a, int left, int right) {
        if (left >= right) {
            return;
        }
        int p = partition(a, left, right); // p代表基准点元素索引}
        quick(a, left, p - 1);
        quick(a, p + 1, right);

    }

    /*
        注意事项：
            1.为啥要加内循环的i<j条件
            2.为啥要先处理j，再处理i
            3.随机元素作为基准点
            4.如果出现了大量重复元素
                循环内
                    i从left+1开始，从左向右找大的或相等的
                    j从right开始，从右向左找小的或相等的
                    交换，i++，j--
                循环外j和基准点交换，j即为分区位置
     */
    private static int partition(int[] a, int left, int right) {
        int index = ThreadLocalRandom.current().nextInt((right - left + 1) + left);
        // [0~9] right-left+1=3 [0,2]+4=[4,6]
        swap(a, index, left);
        int pv = a[left];
        int i = left;
        int j = right;
        while (i < j) {
            // 1.j从👉向左找小的
            while (i < j && a[j] > pv) {
                j--;
            }
            // 2.i从👈向右找大的
            while (i < j && a[i] <= pv) {
                i++;
            }
            // 3.交换位置
            swap(a, i, j);
        }
        swap(a, left, i);
        return i;
    }

    private static void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

}
